from pandac.PandaModules import NetDatagram
from direct.distributed.PyDatagram import PyDatagram
from direct.distributed.PyDatagramIterator import PyDatagramIterator
# task define
from TaskDefine import task_READERPOLLING, task_DEADCONNECTIONCHECKPOLLING
from direct.task import Task
from Cube.utility.TaskMgrWrapper import TaskMgrWrapper
# pack/unpack data
from Cube.utility.PythonObject2String import Object2String, String2Object
# target ID
from IDGen import IDGen

class QNetwork:
    default_Port = 9099
    def __init__(self):
        self.ConnectionTargetDict = {}
        self.TargetIDMgr = IDGen()
        self._taskMgr = TaskMgrWrapper()
        self.ListenerEnable = False
        self.ReadEnable = True

        self.NewConnectionHandle = DefaultNewConnectionHandle
        self.ProcessDataHandle = DefaultProcessDataHandle

    # override
    def Setup(self):
        pass

    def Close(self):
        self._taskMgr.RemoveAll()
        for link in self.ConnectionTargetDict.values():
          self.cReader.removeConnection(link)
        self.cManager.closeConnection(self.tcpSocket)
        self.ConnectionTargetDictReset(0)

    # connection-link and targetID
    def ConnectionTargetDictReset(self, acceptedConnectionNum = 1):
        self.ConnectionTargetDict = {}
        self.TargetIDMgr.MaxIDSlotSet(acceptedConnectionNum)

    def ConnectionTargetAdd(self, targetLink):
        id = self.TargetIDMgr.IDPick()
        self.ConnectionTargetDict[id] = targetLink
        return id

    def ConnectionTarget2ID(self, targetLink):
        index = self.ConnectionTargetDict.values().index(targetLink)
        id = self.ConnectionTargetDict.keys()[index]
        return id

    # data object receive
    def ReaderPollingEnable(self):
        self._taskMgr.Add(self.tskReaderPolling,task_READERPOLLING["name"], task_READERPOLLING["sort"])

    def ReadEnableSet(self, value=True):
        self.ReadEnable = value

    def tskReaderPolling(self, task):
        while self.ReadEnable and self.cReader.dataAvailable():
            datagram=NetDatagram()
            if self.cReader.getData(datagram):
                pkg = PyDatagramIterator(datagram)
                dataObject = String2Object(pkg.getString())
                self.ProcessDataHandle(dataObject)
        return task.cont

    def DeadConnectionIndexGet(self):
        ret = []
        for (i,client) in self.ConnectionTargetDict.items():
            if not self.cReader.isConnectionOk(client):
                ret.append(i)
        return ret

    def ConnectionRemove(self, removeList):
        for i in removeList:
            if self.ConnectionTargetDict.has_key(i):
                self.cReader.removeConnection(self.ConnectionTargetDict[i])
                del self.ConnectionTargetDict[i]
                self.TargetIDMgr.IDRelease(i)

    # data object send
    def DataObjSend(self, dataObj, targetID=IDGen.startID):
        #print 'send:%s'%(dataObj)
        datagram = PyDatagram()
        datagram.addString( Object2String(dataObj) )
        self.cWriter.send(datagram, self.ConnectionTargetDict[targetID])

    def DataObjSendAll(self, dataObj):
        #print 'send all:%s'%(dataObj)
        datagram = PyDatagram()
        datagram.addString( Object2String(dataObj) )
        for link in self.ConnectionTargetDict.values():
            self.cWriter.send(datagram, link)

    def TotoalConnectionNumGet(self):
        ret = len(self.ConnectionTargetDict)
        return ret

    def NewConnectionHandleSet(self, fn):
        self.NewConnectionHandle = fn

    def ProcessDataHandleSet(self, fn):
        self.ProcessDataHandle = fn

    def DeadConnectionHandleSet(self, fn):
        self.DeadConnectionHandle = fn

# default handle
def DefaultNewConnectionHandle(LinkID):
    print "NewConnection - id = %d"%(LinkID)

def DefaultProcessDataHandle(dataObject):
    print "Receive data = %s"%(dataObject)
